#include "map.h"
#include <nds.h>
#include <stdio.h>

map::map(){
	BG0_CR = BG_TILE_BASE(0) | BG_MAP_BASE(8) | BG_COLOR_256 | TEXTBG_SIZE_512x256 | BG_PRIORITY(1) | BG_WRAP_ON;
	BG0_X0 = 0;

	mapSize.x = mapWidth*16;
	mapSize.y = mapHeight*16;

	//BG2_XDX = 1 << 8;
	//BG2_XDY = 0;
	//BG2_YDX = 0;
	//BG2_YDY = 1 << 8;

	//BG3_CR = BG_PRIORITY(2);

	/*for(int x = 0 ; x < mapWidth ; x++){
		for(int y = 0 ; y < mapHeight ; y++){
			if(level_one[x+y*mapWidth]==1){
				metaData[x][y].isCollideable=true;
			}else{
				metaData[x][y].isCollideable=false;
			}
		}
	}*/

	//for(int x=0;x<mapWidth;x++){
	//	for(int y=0;y<mapHeight;y++){
	//		metaData[x][y].isCollideable=false;
	//	}
	//}
	////Maps2 collide info

	//for(int x=5;x<11;x++){
	//	metaData[x][3].isCollideable=true;
	//}

	//for(int x=0;x<3;x++){
	//	metaData[x][6].isCollideable=true;
	//}

	//for(int x=0;x<4;x++){
	//	metaData[x][10].isCollideable=true;
	//}

	//for(int x=14;x<16;x++){
	//	metaData[x][5].isCollideable=true;
	//}

	//for(int x=13;x<16;x++){
	//	metaData[x][11].isCollideable=true;
	//}
	//for(int x=7;x<9;x++){
	//	for(int y=10;y<16;y++){
	//		metaData[x][y].isCollideable=true;
	//	}
	//}

	//for(int x=0;x<16;x++){
	//	for(int y=14;y<16;y++){
	//		metaData[x][y].isCollideable=true;
	//	}
	//}


//Maps5 collide info

}

map::~map(){

}

void map::DisplayMap(const void *src, uint32 size, const void *src1, uint32 size1, const void *src2, uint32 size2){
	//AKS
	//FIXME: Memory locations hardcoded.  Or will a second call
	//replace old map with no problems?
	dmaCopyHalfWords(DmaChannel, src, BG_PALETTE, size);
	dmaCopyHalfWords(DmaChannel, src1, (uint16 *)BG_TILE_RAM(0), size1);
	dmaCopyHalfWords(DmaChannel, src2, (uint16 *)BG_MAP_RAM(8), size2);

	//u16* screenMap = (u16*)BG_MAP_RAM(8);
	//const u16* largeMap = (u16*)src2;
	//int camera_x = 0;
	//int camera_y = 128-96;
	//for(int x=0;x<32;x++){
	//	for(int y=0;y<32;y++){
	//		screenMap[x+y*32]=largeMap[x+y*32];
	//		//screenMap[x + y*32] = largeMap[(x + camera_x/8) + (y + camera_y/8) * 32];
	//	}
	//}

	//screenMap += 31*32;
	//for(int x=32;x<64;x++){
	//	for(int y=0;y<32;y++){
	//		screenMap[x+y*32]=largeMap[x+y*32];
	//		//screenMap[x + y*32] = largeMap[(x + camera_x/8) + (y + camera_y/8) * 32];
	//	}
	//}
}

void map::loadMetaData(int level){
	if(level == 1){
		for(int x = 0 ; x < mapWidth ; x++){
			for(int y = 0 ; y < mapHeight ; y++){
				metaData[x][y].isCollideable=level_one[x+y*mapWidth];
			}	
		}
	}else if(level == 2){
		for(int x = 0 ; x < mapWidth ; x++){
			for(int y = 0 ; y < mapHeight ; y++){
				metaData[x][y].isCollideable=level_two[x+y*mapWidth];
			}	
		}
	}else if(level == 3){
		for(int x = 0 ; x < mapWidth ; x++){
			for(int y = 0 ; y < mapHeight ; y++){
				metaData[x][y].isCollideable=level_three[x+y*mapWidth];
			}	
		}
	}else if(level == 4){
		for(int x = 0 ; x < mapWidth ; x++){
			for(int y = 0 ; y < mapHeight ; y++){
				metaData[x][y].isCollideable=level_four[x+y*mapWidth];
			}	
		}
	}
}

void map::displayBackground(const void *src, uint32 size){
	dmaCopyHalfWords(DmaChannel,src,(uint16 *)BG_BMP_RAM(8),size);
}

void map::displaySubScreen(const void *src, uint32 size){
	dmaCopyHalfWords(DmaChannel,src,(uint16 *)(BG_BMP_RAM_SUB(0) + 8*1024),size);	
}

void map::loadCurrentScreen(t2DVector camera){
	u16* screenMap = (u16*)BG_MAP_RAM(8);
	u16* screenMapRightSBB = screenMap + 31*32;
	//const u16* largeMap = (u16*)Maps5Map;
	const u16* largeMap = (u16*)levelMap;

	int LMIindex;
	int SMIindex;

	int SBBWidth=32;
	int mapWidth_tiles=mapWidth*2;
	int mapHeight_tiles=mapHeight*2;

	int screenWidth=32;	//in tiles
	int	screenHeight=24;//in tiles
	int blockWidth=64;
	int blockHeight=32;
	int cameraX_tiles = (int)(camera.x / 8.0);
	int cameraY_tiles = (int)(camera.y / 8.0);

	for(int i=0;i<screenWidth;i++){
		for(int j=0;j<screenHeight;j++){
			LMIindex = (cameraX_tiles + i) + (cameraY_tiles + j) * mapWidth_tiles;
			SMIindex = (cameraX_tiles +i)%mapWidth_tiles + ((cameraY_tiles+j) % blockHeight) * SBBWidth;
			//AKS
			//FIXME:  Does not load right screen block correctly.
			//not a problem if function is only called when camera is
			//only on left screen block.
			if( (( cameraX_tiles+i) %blockWidth) < SBBWidth){
				screenMap[SMIindex]=largeMap[LMIindex];
			}else{
				screenMapRightSBB[SMIindex]=largeMap[LMIindex];
			}
		}
	}
}
void map::updateMap(t2DVector camera){
	
	u16* screenMap = (u16*)BG_MAP_RAM(8);
	u16* screenMapRightSBB = screenMap + 31*32;
	//const u16* largeMap = (u16*)Maps5Map;
	const u16* largeMap = (u16*)levelMap;

	int LMIindex;
	int SMIindex;

	int SBBWidth=32;
	int mapWidth_tiles=mapWidth*2;
	int mapHeight_tiles=mapHeight*2;

	int screenWidth=32;	//in tiles
	int	screenHeight=24;//in tiles
	int blockWidth=64;
	int blockHeight=32;
	int cameraX_tiles = (int)(camera.x / 8.0);
	int cameraY_tiles = (int)(camera.y / 8.0);

//right side
	for(int i=-1;i<screenHeight+1;i++){
	    LMIindex = (cameraX_tiles + screenWidth) + (cameraY_tiles + i) * mapWidth_tiles;
        SMIindex = (cameraX_tiles + screenWidth) % blockWidth + ((cameraY_tiles+i) % blockHeight) * SBBWidth;

        if( (( cameraX_tiles + screenWidth) %blockWidth) < SBBWidth){              
			screenMap[SMIindex]=largeMap[LMIindex];
        }else{
		    screenMapRightSBB[SMIindex]=largeMap[LMIindex];
        }
    }


//left side
	for(int i=-1;i<screenHeight+1;i++){
		LMIindex = (cameraX_tiles) + (cameraY_tiles + i) * mapWidth_tiles;
		SMIindex = (cameraX_tiles)%blockWidth + ((cameraY_tiles+i)%blockHeight)*SBBWidth;

		if( (( cameraX_tiles) %blockWidth) < SBBWidth){
			screenMap[SMIindex]=largeMap[LMIindex];
		}else{
			screenMapRightSBB[SMIindex]=largeMap[LMIindex];
		}
	}

//bottom side
	for(int i=0;i<screenWidth;i++){
		LMIindex = (cameraX_tiles + i) + (cameraY_tiles+screenHeight)*mapWidth_tiles;
		SMIindex = ((cameraX_tiles + i)%blockWidth) + ((cameraY_tiles+screenHeight) % blockHeight)*SBBWidth;
	

		if(((cameraX_tiles + i)%blockWidth) < SBBWidth){
				screenMap[SMIindex]=largeMap[LMIindex];
		}else{
				screenMapRightSBB[SMIindex]=largeMap[LMIindex];
		}
	}

//top
	for(int i=0;i<screenWidth;i++){
		LMIindex = (cameraX_tiles +i) + (cameraY_tiles)*mapWidth_tiles;
		SMIindex =((cameraX_tiles + i)%blockWidth) + ((cameraY_tiles)%blockHeight)*SBBWidth;
		if(((cameraX_tiles + i)%blockWidth) < SBBWidth){
				screenMap[SMIindex]=largeMap[LMIindex];
		}else{
				screenMapRightSBB[SMIindex]=largeMap[LMIindex];
		}
	}
	
}

void map::setMap(u16* newMap){
	levelMap = newMap;
}

metaTile map::returnTile(int indexX, int indexY){
	return metaData[indexX][indexY];
}

//int map::returnBoundBox(int indexX, int indexY){
//	return metaData[indexX][indexY].bounds;
//}

int map::returnCollideable(int indexX, int indexY){
	return metaData[indexX][indexY].isCollideable;
}

int map::returnIcy(int indexX, int indexY){
	return metaData[indexX][indexY].isCollideable;
}

t2DVector map::getMapSize(){
	return mapSize;
}